const { Middleware , EntityScaner } = require("springbreeze")  ,
    Seneca = require("seneca") 
    // util = require("util") ,

module.exports = class SenecaMiddleware extends Middleware {

    constructor(){
        super()
        this.seneca = Seneca({
            log : {
                level : "warn+"
            } ,
            short : true 
        })
        this.count = 0 
    }

    before(){
        this.loadClient()
        this.loadServer()
        this.beforeFunc = this.config().before || function( v ){ return v}
        this.afterFunc = this.config().after || function( v ){ return v }
    }

    pin( value ){
        if( value ) {
            if( this.pins ) {
                this.pins += "," 
            }else this.pins = ""
            this.pins += value + ":*"
        }
        return this.pins 
    }
    
    async start() {
        if( this.count > 0 ) {
            Log.info("Seneca server listen at [%d]" , this.config().port)
            this.seneca.listen({
                type : this.config().type || "tcp", 
                host : this.config().host || "0.0.0.0" ,
                port : this.config().port || 10077,
                pin : this.pin() 
            })
        }
    }

    addService( service ) {
        const app = this 
        Log.info("-->加载Seneca服务[%s][%s]" , service.name() , service.__path )
        this.pin( service.name() )  //添加pin
        const fns = service.fns 
        for( let index in fns ) {
            const fn = fns[ index ]
            Log.info("--->加载子服务[%s]" , fn.cmd  )
            this.count = this.count + 1 
            this.seneca.add( fn.cmd , function(msg , done ) {
                //TODO 可增加前处理，已解决参数验证或者加工请求数据等问题
                msg = app.beforeFunc( msg )
                fn.fn( msg , app.service()).then( ret => {
                    const tx = msg["tx$"]
                    Log.debug("Seneca[%s]请求参数:" , tx , msg )
                    ret = ret || {
                        code : 0 ,
                        info : "ok" ,
                        data : null 
                    }
                    //需要考虑 ret.code 为0的情况
                    if( !ret["code"] && ret["code"] != 0 ){
                        ret = {
                            code : 0 ,
                            info : "ok" ,
                            data : ret 
                        } 
                    }

                    ret = app.afterFunc( ret )
                    Log.debug( "Seneca[%s]响应" , tx , ret  )
                    done( null , ret )
                }).catch( e => {
                    //done( e , {})
                    GetLogger("error").error("调用服务异常：%s " , e )
                    done( null , {
                        code : 11 , 
                        info : e.description || e.message  ,
                        data : null 
                    })
                })
                //格式化ret,采用springbreeze/Ret
            })
            // this.seneca.add( fn.cmd , fn.fn )
        }
    }

    after(){

    }

    async act(  selector , request ) {
        const app = this 
        return new Promise( function(resolve , reject ) { 
            app.seneca.act( selector , request , function( err , result ){
                if( err ) reject( err )
                else resolve( result )
            })
        })
    }

    loadClient(){
        let clients = this.config().clients
        clients = clients || []     //兼容错误
        Log.info("-->加载客户端配置,共[%d]个客户端" , clients.length )
        for( let idx in clients ){
            const client = clients[ idx ]
            client.type = client.type || "tcp"
            Log.info("--->加载客户端[%s][%s][%d][%s]" , 
                client.type , client.host , client.port , client.pin )
            this.seneca.client( client )
        }
    }

    loadServer(){
        const path = this.config().serverPath 
        if( !path ) {
            Log.info("未配置服务目录,跳过扫描。")
            return 
        }
        Log.info("开始Seneca服务，扫描目录: [%s]" , path )
        const routerScaner = new EntityScaner()
        routerScaner.setNextPath( path )
        const services = routerScaner.scan() 
        for( let idx in services ){
            const service = services[ idx ]
            if( service ){
                this.addService( service )
            }
        }
    }

}